package no.sachmuld.methodcombination.examples.reflection.validate;

import no.sachmuld.methodcombination.api.MethodCombinationSupport;
import no.sachmuld.methodcombination.api.MethodInvocation;
import no.sachmuld.methodcombination.api.reflection.Default;
import no.sachmuld.methodcombination.api.reflection.MethodCombinationValidator;
import no.sachmuld.methodcombination.api.reflection.component.DelegatingMethodCombination;
import no.sachmuld.methodcombination.api.reflection.component.MethodCombination;
import no.sachmuld.methodcombination.impl.validate.MethodCombinationValidationError;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
public class Foo extends MethodCombinationSupport<FooBehaviour> {

    private static DelegatingMethodCombination<Object, Integer> bar = new Default<Integer>().build(FooBehaviour.class, Foo.class, "bar");
    private static DelegatingMethodCombination<Object, Integer> baz = new Default<Integer>().build(FooBehaviour.class, Foo.class, "baz");

    private static Map<Method, MethodCombination> methodCombinationMap = new HashMap<>();

    static {
        try {
            methodCombinationMap.put(Foo.class.getDeclaredMethod("bar"), bar);
            methodCombinationMap.put(Foo.class.getDeclaredMethod("baz"), baz);
        } catch (NoSuchMethodException e) {
            e.printStackTrace(System.err);
        }
    }

    public static List<MethodCombinationValidationError> validate() {
        return new MethodCombinationValidator(FooBehaviour.class, Foo.class, methodCombinationMap).validate();
    }

    public Foo() {
        with(new FooBehaviour() {
            @Override
            protected int bar(MethodInvocation<Integer> methodInvocation) {
                return 7;
            }

            @Override
            protected int baz(MethodInvocation<Integer> methodInvocation) throws FooException {
                throw new FooException();
            }
        });

    }

    public final int bar() {
        return bar.execute(this, chain());
    }

    public final int baz() throws FooException {
        return baz.throwing(FooException.class).execute(this, chain());
    }

}
